package com.ifacebox.software.updater;

import java.awt.BorderLayout;
import java.awt.Image;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import javax.swing.*;

/**
 * @author znn
 */
public class SoftwareUpdaterFrame extends JFrame implements SoftwareUpdaterCallback {
    private static final long serialVersionUID = 1L;
    private static final int CORE_POOL_SIZE = 1;
    private static final int ONE_SECOND_TIME = 1000;
    private static final int AUTO_UPDATER_SECOND = 5;
    private static final String PROGRESS_MESSAGE = "%.2fKB/s - %.2fMB/%.2fMB 剩余%s";
    private JProgressBar softwareUpdaterProgressBar;
    private JLabel softwareUpdaterProgressTitle, softwareUpdaterProgressMessage;
    private final SoftwareUpdaterService softwareUpdaterService;
    private final SoftwareUpdaterExceptionDialog softwareUpdaterExceptionDialog;
    private final SoftwareUpdaterSetupDialog softwareUpdaterSetupDialog;
    private final ScheduledExecutorService scheduledExecutorService;
    private ScheduledFuture<?> scheduledFuture = null;

    public SoftwareUpdaterFrame(String softwareUpdaterAddress, String softwareUpdaterName) {
        this(null, false, softwareUpdaterAddress, softwareUpdaterName);
    }

    public SoftwareUpdaterFrame(JFrame frame, boolean autoSoftwareUpdater, String softwareUpdaterAddress, String softwareUpdaterName) {
        this(frame == null ? null : frame.getTitle(), frame == null ? null : frame.getIconImage(), autoSoftwareUpdater, softwareUpdaterAddress, softwareUpdaterName);
    }

    public SoftwareUpdaterFrame(String softwareUpdaterTitle, Image softwareUpdaterImage, boolean autoSoftwareUpdater, String softwareUpdaterAddress, String softwareUpdaterName) {
        super.setTitle(softwareUpdaterTitle == null ? "SoftwareUpdater" : softwareUpdaterTitle);
        super.setIconImage(softwareUpdaterImage == null ? new ImageIcon(this.getClass().getResource("/ifacebox-logo.png")).getImage() : softwareUpdaterImage);
        super.setResizable(false);
        super.setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
        super.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
            }
        });
        super.add(new JPanel() {
            private static final long serialVersionUID = 1L;

            {
                this.setLayout(new BorderLayout());
                this.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
                this.add(softwareUpdaterProgressBar = new JProgressBar(), BorderLayout.NORTH);
                this.add(softwareUpdaterProgressTitle = new JLabel(" "), BorderLayout.CENTER);
                this.add(softwareUpdaterProgressMessage = new JLabel(PROGRESS_MESSAGE), BorderLayout.SOUTH);
            }
        });
        this.softwareUpdaterProgressBar.setStringPainted(true);
        this.softwareUpdaterProgressTitle.setBorder(BorderFactory.createEmptyBorder(5, 5, 0, 5));
        this.softwareUpdaterProgressMessage.setBorder(BorderFactory.createEmptyBorder(0, 5, 5, 5));
        this.softwareUpdaterService = new SoftwareUpdaterService(softwareUpdaterAddress, softwareUpdaterName);
        this.softwareUpdaterExceptionDialog = new SoftwareUpdaterExceptionDialog(this);
        this.softwareUpdaterSetupDialog = new SoftwareUpdaterSetupDialog(this);
        this.scheduledExecutorService = new ScheduledThreadPoolExecutor(CORE_POOL_SIZE
                , r -> new Thread(r, "ShowSoftwareUpdater-Scheduled"));
        this.addAutoSoftwareUpdater(autoSoftwareUpdater);
    }

    public synchronized void addAutoSoftwareUpdater(boolean autoSoftwareUpdater) {
        if (autoSoftwareUpdater) {
            this.scheduledFuture = this.scheduledExecutorService.schedule(() -> {
                try {
                    this.showSoftwareUpdater();
                } finally {
                    this.scheduledFuture.cancel(false);
                }
            }, AUTO_UPDATER_SECOND, TimeUnit.SECONDS);
        }
    }

    public synchronized boolean showSoftwareUpdater() {
        if (super.isVisible()) {
            return false;
        }
        super.pack();
        super.setAlwaysOnTop(true);
        super.setLocationRelativeTo(null);
        super.setVisible(true);
        return this.softwareUpdaterService.updater(this);
    }

    public void showSetupSoftwareUpdater(String softwareUpdaterAddress, String softwareUpdaterName, SoftwareUpdaterSetupCallback softwareUpdaterSetupCallback) {
        this.softwareUpdaterSetupDialog.show(softwareUpdaterAddress, softwareUpdaterName, softwareUpdaterSetupCallback);
    }

    public void setSoftwareUpdaterProgressTitle(String title) {
        for (int i = AUTO_UPDATER_SECOND; i > 0; i--) {
            this.softwareUpdaterProgressTitle.setText(String.format(title, i));
            super.pack();
            try {
                Thread.sleep(ONE_SECOND_TIME);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }

    @Override
    public void onSoftwareUpdaterPrepared(SoftwareUpdaterConfig softwareUpdaterConfig) {
        this.softwareUpdaterProgressBar.setValue(this.softwareUpdaterProgressBar.getMinimum());
        this.softwareUpdaterProgressTitle.setText("正在连接软件升级服务器，请稍后...");
        this.softwareUpdaterProgressMessage.setText(String.format(PROGRESS_MESSAGE, 0.0, 0.0, 0.0, "0秒"));
        super.pack();
    }

    @Override
    public boolean onSoftwareUpdaterStart(boolean isSoftwareUpdater, SoftwareUpdaterConfig softwareUpdaterConfig) {
        if (isSoftwareUpdater) {
            this.setSoftwareUpdaterProgressTitle("发现新版本，【%s】秒后开始下载升级文件...");
        } else {
            this.setSoftwareUpdaterProgressTitle("软件不需要升级，【%s】秒后关闭...");
        }
        return isSoftwareUpdater;
    }

    @Override
    public void onSoftwareUpdaterFinish(SoftwareUpdaterConfig softwareUpdaterConfig) {
        if (softwareUpdaterConfig != null) {
            this.softwareUpdaterProgressBar.setValue(this.softwareUpdaterProgressBar.getMaximum());
            this.setSoftwareUpdaterProgressTitle("下载完成，【%s】秒后开始安装...");
            if (softwareUpdaterConfig.getFileSoftware() != null && softwareUpdaterConfig.getFileSoftware().exists()) {
                this.softwareUpdaterService.install(softwareUpdaterConfig.getFileSoftware());
            } else {
                JOptionPane.showMessageDialog(this, "安装失败，请检查安装文件是否存在！", this.getTitle(), JOptionPane.ERROR_MESSAGE);
            }
        }
        super.setVisible(false);
    }

    @Override
    public void onSoftwareUpdaterFailed(SoftwareUpdaterException error) {
        super.setVisible(false);
        SwingUtilities.invokeLater(() -> this.softwareUpdaterExceptionDialog.show(error.getErrorMsg()));
    }

    @Override
    public void onSoftwareUpdaterChanged(long totalSize, long totalWrite, long secondWrite) {
        // 下载百分比=已下载大小/总大小*100
        int value = (int) ((double) totalWrite / (double) totalSize * 100);
        // 剩余下载时间=(总大小-已下载大小)/每秒下载大小
        long second = secondWrite > 0 ? ((totalSize - totalWrite) / secondWrite) : 0;
        this.softwareUpdaterProgressBar.setValue(value);
        this.softwareUpdaterProgressTitle.setText("下载中，请稍后...");
        this.softwareUpdaterProgressMessage.setText(String.format(PROGRESS_MESSAGE,
                ((double) secondWrite / 1024),
                ((double) totalWrite / 1024 / 1024),
                ((double) totalSize / 1024 / 1024),
                SoftwareUpdaterService.formatDuration(second * 1000)));
        super.pack();
    }

}
